﻿// --------------------------------------------------------------------------------------------------------------------
// <copyright file="RenameDialog.xaml.cs" company="GT">
//   Gunther Taborga
// </copyright>
// <summary>
//   Interaction logic for RenameDialog.xaml
// </summary>
// --------------------------------------------------------------------------------------------------------------------

// TODO refactored=true
namespace BatchID3.Editor.Dialogs
{
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Linq;
    using System.Windows;
    using System.Windows.Controls;

    using BatchID3.Enumerations;
    using BatchID3.Extensions;
    using BatchID3.Mp3;

    public partial class RenameDialog : Window, IRenameDialog
    {
        private readonly IMp3FileSystemManager mp3FileSystemManager;

        private readonly IMp3Entity previewMp3Entity;

        private readonly IEnumerable<IMp3Entity> selectedMp3Entities;

        public RenameDialog()
        {
            this.InitializeComponent();
        }

        public RenameDialog(
            IMp3FileSystemManager mp3FileSystemManager, 
            IMp3PreviewFactory mp3PreviewFactory, 
            IEnumerable<IMp3Entity> mp3Entities,
            IEnumerable<TagToken> tagTokens,
            IEnumerable<TagToken> preSelectedTagTokens,
            IEnumerable<char> delimiters)
        {
            this.InitializeComponent();

            this.mp3FileSystemManager = mp3FileSystemManager;
            this.previewMp3Entity = mp3PreviewFactory.GetMp3Preview();
            this.selectedMp3Entities = mp3Entities;
            this.Setup(tagTokens, preSelectedTagTokens, delimiters);
        }

        public event RenameProgressChangedEventHandler RenameProgressChanged;

        private IEnumerable<TagToken> SelectedTagTokens 
        { 
            get
            {
                return this.tagTokenMultiSelectBox.SelectedTagTokens;
            }
        }

        private object SelectedDelimiter
        {
            get
            {
                return this.delimiterComboBox.SelectedItem;
            }
        }

        private void CancelButtonClick(object sender, RoutedEventArgs e)
        {
            this.CloseDialog(false);
        }

        private void CloseDialog(bool dialogResult = true)
        {
            this.DialogResult = dialogResult;
            this.Close();
        }

        private void ListBoxSelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            this.UpdatePreviewLabel();
        }

        private void OkButtonClick(object sender, RoutedEventArgs e)
        {
            this.RenameSelectedMp3Files();
            this.CloseDialog();
        }

        private void RenameSelectedMp3Files()
        {
            if (!this.SelectedTagTokens.Any() || this.SelectedDelimiter == null)
            {
                return;
            }

            var renameWorker = new BackgroundWorker { WorkerReportsProgress = true };
            renameWorker.DoWork += this.RenameWorkerDoWork;
            renameWorker.ProgressChanged += this.RenameWorkerProgressChanged;
            renameWorker.RunWorkerCompleted += this.RenameWorkerRunWorkerCompleted;
            renameWorker.RunWorkerAsync(new RenameArgument(this.selectedMp3Entities, this.SelectedTagTokens, (char)this.SelectedDelimiter));
        }

        private void RenameWorkerDoWork(object sender, DoWorkEventArgs e)
        {
            var backgroundWorker = (BackgroundWorker)sender;
            var args = (RenameArgument)e.Argument;
            var mp3Entities = args.Mp3Entities.ToList();

            for (var i = 0; i < mp3Entities.Count; i++)
            {
                var mp3 = mp3Entities[i];
                var newFilePath = this.mp3FileSystemManager.RenameById3(mp3, args.TagTokens, args.Delimiter);

                backgroundWorker.ReportProgress(i.PercentOf(mp3Entities.Count), new RenameProgressChangedState(mp3, newFilePath));
            }
        }

        private void RenameWorkerProgressChanged(object sender, ProgressChangedEventArgs e)
        {
            var renameState = (RenameProgressChangedState)e.UserState;
            renameState.Mp3Entity.FilePath = renameState.NewFilePath;

            this.RaiseRenameProgessChangedEvent(e);
        }

        private void RaiseRenameProgessChangedEvent(ProgressChangedEventArgs e)
        {
            if (this.RenameProgressChanged != null)
            {
                this.RenameProgressChanged(this, new RenameProgressChangedEventArgs(e.ProgressPercentage));
            }
        }

        private void RenameWorkerRunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            this.RaiseRenameProgressChangedEvent();
        }

        private void RaiseRenameProgressChangedEvent()
        {
            if (this.RenameProgressChanged != null)
            {
                this.RenameProgressChanged(this, new RenameProgressChangedEventArgs(0));
            }
        }

        private void UpdatePreviewLabel()
        {
            if (this.SelectedDelimiter == null)
            {
                this.previewLabel.Content = string.Empty;
                return;
            }

            var newFilePath = this.mp3FileSystemManager.GetNewFileNameFromId3(
                                        this.previewMp3Entity, 
                                        this.SelectedTagTokens, 
                                        (char)this.SelectedDelimiter);

            var fileName = this.mp3FileSystemManager.FileSystem.GetFileName(newFilePath);
            this.previewLabel.Content = string.Format("..{0}{1}", this.mp3FileSystemManager.FileSystem.DirectorySeparatorChar, fileName);
        }

        private void Setup(IEnumerable<TagToken> tagTokens, IEnumerable<TagToken> preSelectedTagTokens, IEnumerable<char> delimiters)
        {
            this.tagTokenMultiSelectBox.SetTagTokens(tagTokens);
            this.tagTokenMultiSelectBox.SetupSelectedTokens(preSelectedTagTokens);
            this.SetupDelimiters(delimiters);

            // Set before SelectionChanged handler that way
            // we only modify the label once at load time
            this.UpdatePreviewLabel();
            this.tagTokenMultiSelectBox.ListBox.SelectionChanged += this.ListBoxSelectionChanged;
        }

        private void SetupDelimiters(IEnumerable<char> delimiters)
        {
            foreach (var delimiter in delimiters)
            {
                this.delimiterComboBox.Items.Add(delimiter);    
            }

            if (this.delimiterComboBox.Items.Count == 0)
            {
                return;
            }
            
            this.delimiterComboBox.SelectedIndex = 0;
        }
    }
}